HTMLify

app.js
Views: 41 | Author: cody
/* Please view in Chrome for best effects! :) */

// Configure
var MAX_DISTANCE  = 200,
    PARTICLES     = 40,
    PARTICLE_SIZE = 5;

// No configure! :p
Math.Tau = Math.PI * 2;
Math.rand = function rand(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
};

Math.map = function map(value, imin, imax, omin, omax) {
  return ((value - imin) * (omax - omin) / (imax - imin) + omin);
};

window.requestAnimFrame = (function(){
  return window.requestAnimationFrame    ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame    ||
    function( callback ){
      window.setTimeout(callback, 1000 / 60);
    };
})();

window.addEventListener('load', function(event) {
  var canvas  = document.getElementById('c');
  var context = canvas.getContext('2d');
  var width, height;
  var particleCounter = 0,
      hover = false,
      stats = new Stats(),
      mmon = new MousePositionMonitor(),
      is_firefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;

  stats.setMode(0); // Start off with FPS mode

  // Place the statistics at the bottom right.
  stats.domElement.style.position = 'absolute';
  stats.domElement.style.right = '5px';
  stats.domElement.style.bottom = '5px';
  
  document.body.appendChild(stats.domElement);
  
  context.lineWidth = "hairline";
  
  var resize = function(event) {
    width  = canvas.width  = window.innerWidth;
    height = canvas.height = window.innerHeight;
  }; resize();
  
  window.addEventListener('resize', resize);
  
  canvas.addEventListener('mouseenter', function() {
    hover = true;
  });

  canvas.addEventListener('mouseleave', function() {
    hover = false;
  });
  
  var Color = function Color(r, g, b, a) {
    this.r = Math.floor(r);
    this.g = Math.floor(g);
    this.b = Math.floor(b);
    this.a = Math.floor(a || 255);
  };
  
  Color.prototype.clone = function() {
    return new Color(this.r, this.g, this.b, this.a);
  };
  
  Color.prototype.toString = function() {
    if(this.a === 255) {
      return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
    } else {
      return 'rgba(' + this.r + ', ' + this.g + ', ' + this.b + ', ' + (this.a / 255) + ')';
    }
  };
  
  var Particle = function Particle(x, y, size, color) {
    this.x  = x;
    this.y  = y;
    this.s  = size;
    this.r  = size / 2;
    this.vx = (Math.random() < 0.5 ? -1 : 1) * Math.rand(0.5, 2);
    this.vy = (Math.random() < 0.5 ? -1 : 1) * Math.rand(0.5, 2);
    this.id = particleCounter++;
    
    if(color instanceof Color) {
      this.c = color;
    } else {
      this.c = new Color(255, 255, 255, 255);
    }
  };
  
  Particle.prototype.distance = function(that) {
    if(that instanceof Particle) {
      return Math.sqrt((this.x-that.x) * (this.x - that.x) + (this.y - that.y) * (this.y - that.y));
    }
  };
  
  Particle.prototype.step = function() {
    this.x = (this.x + this.vx);
    if(this.x < this.r) {
      this.x = this.r;
      this.vx *= -1;
    } else if(this.x > width - this.r) {
      this.x = width - this.r;
      this.vx *= -1;
    }
    
    this.y = (this.y + this.vy);
    if(this.y < this.r) {
      this.y = this.r;
      this.vy *= -1;
    } else if(this.y > height - this.r) {
      this.y = height - this.r;
      this.vy *= -1;
    }
  };
  
  Particle.prototype.render = function() {
    context.fillStyle = this.c.toString();
    context.beginPath();
    context.arc(this.x, this.y, Math.floor(this.s / 2), 0, Math.Tau, false);
    context.closePath();
    context.fill();
  };
  
  var particles = [];
  for(var i = 0; i < PARTICLES - 1; i++) {
    particles.push(
      new Particle(
        Math.random() * width, 
        Math.random() * height, 
        PARTICLE_SIZE, 
        new Color(
          Math.random() * 255, 
          Math.random() * 255, 
          Math.random() * 255, 
          255)
      )
    );
  }
  
  // this one is controllable by mouse movement.
  var mouseParticle = new Particle(
    Math.random() * width, 
    Math.random() * height, 
    PARTICLE_SIZE * 2, 
    new Color(0, 200, 100, 255)
  );
  
  mouseParticle.imp = true;
  
  particles.push(mouseParticle);

  var render = function() {
    //context.clearRect(0, 0, width, height);
    context.fillStyle = 'rgba(0, 0, 0, 0.3)';
    context.fillRect(0, 0, width, height);
    
    // render all the particles and check distances
    var paired = {};
    var ipart  = PARTICLES;
    while(ipart--) {
      var p1    = particles[ipart];
      var jpart = ipart;
      
      p1.step();
      if(p1.imp && hover) {
        var pos = mmon.getMousePosition();
        p1.x = pos.x;
        p1.y = pos.y;
      }
      p1.render();
      
      while(jpart--) {
        var p2 = particles[jpart];
        
        if(p1 !== p2 && !paired[p1.id + '-' + p2.id] && !paired[p2.id + '-' + p1.id]) {
          var distance = p1.distance(p2);
          if(distance < MAX_DISTANCE) {
            if(!is_firefox) {
              var grd = context.createLinearGradient(p1.x, p1.y, p2.x, p2.y),
                  c1 = p1.c.clone(), c2 = p2.c.clone();

              c1.a = c2.a = Math.floor(Math.map(distance, MAX_DISTANCE, 0, 0, 255));

              grd.addColorStop(0, c1), grd.addColorStop(1, c2);

              context.strokeStyle = grd;
            } else {
              var c = p1.c.clone();
              c.a = Math.floor(Math.map(distance, MAX_DISTANCE, 0, 0, 255));
              context.strokeStyle = c.toString();
            }
            
            context.beginPath();
              context.moveTo(p1.x, p1.y);
              context.lineTo(p2.x, p2.y);
            context.closePath();
            context.stroke();
            
            paired[p1.id + '-' + p2.id] = paired[p2.id + '-' + p1.id] = true;
          }
        }
      }
    }
  };
  
  var loop = function() {
    requestAnimFrame(loop);
    stats.begin();
    render();
    stats.end();
  }; loop();
});

Comments